home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Libris Britannia 4
/
science library(b).zip
/
science library(b)
/
DTP
/
DTP_TEX
/
H220.ZIP
/
ITRNS211.ZIP
/
SRC
/
ICHAR.C
< prev
next >
Wrap
C/C++ Source or Header
|
1991-10-13
|
15KB
|
464 lines
/*
*==========================================================================
* Copyright 1991 Avinash Chopde, All Rights Reserved.
*
* Permission to use, copy, modify and distribute this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that
* copyright notice and this permission notice appear in supporting
* documentation, and that the name of Avinash Chopde not be used in
* advertising or publicity pertaining to distribution of the software
* without specific, written prior permission.
* Avinash Chopde makes no representations about the suitability of this
* software for any purpose.
* It is provided "as is" without express or implied warranty.
*
* AVINASH CHOPDE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
* IN NO EVENT SHALL AVINASH CHOPDE BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* OF THIS SOFTWARE.
*
* Author: Avinash Chopde, 1991
* C2 Colonial Drive #4, Andover, MA 01810, USA.
*
*/
#include "itrans.h"
static char S_RCSID[] = "$Header: e:/itrans/src/rcs/ichar.c 1.4 91/10/13 16:49:34 avinash Exp $";
/* =================================================================== */
static int S_get_cus_form(font_t* fptr, /* the font data structure to use */
letter_t dlet, /* letter searched for */
comp_unit_t** cus, /* will return a pointer to the cus here */
comp_unit_t** imp, /* will return implicit char creation ptr */
int* lastform,
int* lastlig); /* whether last two cons have a ligature */
static int S_add_cus(pschar_t psfm[], comp_unit_t* pcu, comp_unit_t cu);
/* =================================================================== */
/* Handle a letter (possibly complex) */
/******
(font_t* fptr, the font data structure to use
letter_t dlet, letter to convert
comp_unit_t pcus[], the comp units that make this
letter - all u_pschar are valid
PostScript codes, or NO_PSCHAR
int size_pcus, array size of ecus- number of elements
int *ox, int *oy, the orgin of this letter
int *width) the width of this complete letter
********/
int make_letter(font_t* fptr,
letter_t dlet,
comp_unit_t pcus[],
int size_pcus,
int *ox, int *oy,
int *width)
{
int num_pcus; /* number of postscript chars that were added to pcus */
int pcode;
comp_unit_t* lcus; /* comp units that make the form of
* the given letter dlet
*/
comp_unit_t* icus; /* comp units that make the implicit form
* of the given letter dlet
*/
comp_unit_t* startcus;
letter_t rcons; /* for recursive calls */
int x1, y1, w, i, j, c1, c2, lastform, nolig, lastlig;
num_pcus = 0;
*ox = *oy = 0;
*width = 0;
x1 = y1 = w = 0;
#ifdef DEBUG
fprintf(stderr, "in make_letter\n");
#endif
if (!S_get_cus_form(fptr, dlet, &lcus, &icus, &lastform, &lastlig)) {
/* some error, illegal char, incomplete fptr
* data structure, etc
*/
return 0; /* 0 elements added */
}
/* collect all the PS chars in lcus into the output array */
while (lcus) {
/* get the PS code of this unit */
pcode = lcus->u_pschar;
#ifdef DEBUG
fprintf(stderr, "while lcus in make_letter: pcode is %d\n", pcode);
#endif /*DEBUG*/
if (pcode == NO_PSCHAR || (pcode >= 0 && pcode <= 255)) {
/* valid PostScript code */
num_pcus += S_add_cus(fptr->psfm, &pcus[num_pcus], *lcus);
/* update origin and width */
/* XXX need to track bounding boxes etc */
} else if (pcode == IMPLICIT_PSCHAR && icus) {
/* Need to use the implicit char description, and have a
* valid pointer to comp_units that compose the implicit
* char.
*/
startcus = icus;
while (startcus) {
#ifdef DEBUG
fprintf(stderr, "while startcus in make_letter: pcode is %d\n", pcus[num_pcus-1].u_pschar);
#endif /*DEBUG*/
/* error check */
if ( startcus->u_pschar != NO_PSCHAR &&
(startcus->u_pschar < 0 || startcus->u_pschar > 255)) {
fprintf(stderr, "ERROR: %d illegal pschar in implicit comp units\n", startcus->u_pschar);
} else {
num_pcus += S_add_cus(fptr->psfm,&pcus[num_pcus],*startcus);
}
startcus = startcus->next;
}
} else if (pcode == IMPLICIT_PSCHAR) {
/* implies that no implicit char defined for this letter, and
* the letter is complex, and has to be split into
* simpler parts
* The way it is done is that every consonant is
* printed out in HALF_FORM, except the last
* consonant, which is printed out in its IMPLICIT_FORM.
************
* What to do here is driven by the CONSONANTS_MANY case
* in S_get_cus_root()
* Of course, be careful, this could also be CONS..DOUBLE...
* in case the IFM file contains SAME_AS CCS statements
* but no implicit char defns...
*/
#ifdef DEBUG
fprintf(stderr, "make_letter: pcode IMPLICIT, no icus, looping for halfforms\n");
#endif /*DEBUG*/
for (i = 0; i < dlet.n; i ++) {
#ifdef DEBUG
fprintf(stderr, "make-letter i %d dlet.n %d lastlig %d\n", i, dlet.n, lastlig);
#endif
/* check if a ligature has been defined for
* (current char, next char) pair, use it if available
*/
if (i < (dlet.n-1)) { /* i.e, two more consonants left..*/
c1 = _I_(dlet.cons[i]); c2 = _I_(dlet.cons[i+1]);
if (i == (dlet.n-1)) j = lastform; /* last chars */
else j = HALF_FORM; /* still more to come,so use halfform*/
nolig = ((dlet.nolig[i]) || (lastlig && i == (dlet.n-3)));
#ifdef DEBUG
fprintf(stderr, "makeletter nolig %d\n", nolig);
#endif
/* if last lig exists, do not use the
* secondlast consonant with the thirdlast consonant.
* -- just display the thirdlast consonant in
* half form.
*/
if (!nolig && fptr->ligatures[c1][c2].cus &&
fptr->ligatures[c1][c2].cus[IMPLICIT_FORM]) {
/* just check for existence of the IMPLICIT_FORM-
* if it exists, the half-form will also
* exist---other way around is not true!.
*/
#ifdef DEBUG
fprintf(stderr, "C1: %d, C2 %d, cus(%d)\n", c1, c2,
fptr->ligatures[c1][c2].cus[j]);
#endif /*DEBUG*/
/* found ligature! */
if (i == (dlet.n-2)) j = lastform; /* last chars */
else j = HALF_FORM; /* more to come,so use halfform*/
rcons.n = 2; rcons.v = j;
rcons.type = CONSONANT_DOUBLE_TYPE;
rcons.cons[0] = dlet.cons[i];
rcons.cons[1] = dlet.cons[i+1];
rcons.nolig[0] = FALSE;
i++; /* have used up next char too */
} else {
/* no ligature defined, draw a half form */
rcons.n = 1; rcons.v = HALF_FORM;
rcons.type = CONSONANT_SINGLE_TYPE;
rcons.cons[0] = dlet.cons[i];
}
} else { /* this is the last char */
rcons.n = 1; rcons.v = lastform;
rcons.type = CONSONANT_SINGLE_TYPE;
rcons.cons[0] = dlet.cons[i];
}
j = make_letter(fptr, rcons, &pcus[num_pcus],
size_pcus - num_pcus, &x1, &y1, &w);
/* recompute origin, width */
num_pcus += j;
}
} else { /* ERROR */
fprintf(stderr, "ERROR ERROR: %d illegal pschar in Form comp units\n", pcode);
}
lcus = lcus->next;
} /* while (lcus) */
#ifdef DEBUG
fprintf(stderr, "make_letter::created CUS containging %d cus\n", num_pcus);
#endif /*DEBUG*/
/* keep the next pointers in the pcus correct */
for (i = 0; i < num_pcus; i ++) {
pcus[i].next = &pcus[i+1];
}
if (num_pcus > 0) pcus[num_pcus-1].next = NULL;
return num_pcus;
} /* make_letter() */
/* =================================================================== */
static comp_unit_t S_implicit_cu = {IMPLICIT_PSCHAR, 0, 0, 0, NULL};
static int S_get_cus_form(font_t* fptr, /* the font data structure to use */
letter_t dlet, /* letter searched for */
comp_unit_t** cus, /* will return a pointer to the cus here */
comp_unit_t** imp, /* will return implicit char creation ptr */
int* lastform,
int* lastlig)
/* lastform: CONSDOUBLE/MANY return form to use
* of the last consonant (usually
* IMPLICIT_FORM)
*/
/* lastlig: will return TRUE if the last two
* two consonants have a ligature
*/
{
int i, form, c1, c2, c2only, found, nolig;
comp_unit_t *clist, *lcus;
comp_unit_t *cimp;
dchar_t dc, *next;
*cus = NULL;
*imp = NULL;;
*lastlig = FALSE;
c2only = FALSE; /* flag is used for CONSDOUBLE/CONSMANY forms.
* If the ligature is not found, then the whole
* character is assumed to follow the form
* for the c2 consonant.
* BUT, that implies that the clist for c2
* contains a reference to the "implicit" char,
* so that c1-half-form also gets printed
* (by a recursive call).
* If c2 does not contain a reference to an
* implicit char, then one is stuffed in.
*/
form = dlet.v;
if (form != HALF_FORM && form != IMPLICIT_FORM) form = _I_(form);
c1 = _I_(dlet.cons[0]);
c2 = _I_(dlet.cons[1]);
nolig = dlet.nolig[0]; /* if TRUE, then do not use ligature */
dc.cus = NULL;
dc.same_as = NULL;
clist = NULL;
cimp = NULL;
#ifdef DEBUG
fprintf(stderr, "get ccus form for: c1 %d, c2 %d, form %d type %d\n", c1, c2, form, dlet.type);
#endif /*DEBUG*/
switch (dlet.type) {
case CONSONANT_SINGLE_TYPE:
dc = fptr->khadi[c1];
if (dc.cus) {
clist = dc.cus[form];
cimp = dc.cus[IMPLICIT_FORM];
#ifdef DEBUG
fprintf(stderr, "conssingle: clist is %d cimp %d\n", (int)clist, (int)cimp);
#endif /*DEBUG*/
}
break;
case CONSONANT_DOUBLE_TYPE:
*lastform = IMPLICIT_FORM;
if (!nolig) {
dc = fptr->ligatures[c1][c2];
if (dc.cus) {
*lastlig = TRUE;
clist = dc.cus[form];
cimp = dc.cus[IMPLICIT_FORM];
}
}
/* If clist is NULL, and same_as is NULL,
* consider the last consonant, and follow the form for
* its CONS..SINGLE form
* NOTE: cimp cannot be looked for!
*/
#ifdef DEBUG
fprintf(stderr, "consdouble: before same_as clist is %d cimp %d (sameas %d)\n", (int)clist, (int)cimp, dc.same_as);
#endif /*DEBUG*/
if (!clist && !dc.same_as) {
dc = fptr->khadi[c2]; /* to follow same_as ptr */
if (dc.cus) {
clist = dc.cus[form];
c2only = TRUE;
}
}
#ifdef DEBUG
fprintf(stderr, "consdouble: after same_as clist is %d cimp %d (new sameas %d)\n", (int)clist, (int)cimp, dc.same_as);
#endif /*DEBUG*/
break;
case CONSONANT_MANY_TYPE:
*lastform = IMPLICIT_FORM;
c1 = _I_(dlet.cons[dlet.n - 2]);
c2 = _I_(dlet.cons[dlet.n - 1]);
nolig = dlet.nolig[dlet.n-2]; /* if TRUE, then do not use ligature */
/* if many consonants, two possibilities:
* consider the last two consonants, and follow the form for
* their ligature....
* (Note that this sometimes creates wrong characters,
* especially with the ra-cons-cons ligatures....
* (User can always prevent this by using the NOLIG_TOK - {} chars
* in the input
*/
if (!nolig) {
dc = fptr->ligatures[c1][c2];
if (dc.cus) {
clist = dc.cus[form];
*lastlig = TRUE;
}
#ifdef DEBUG
fprintf(stderr, "consmany: before same_as clist is %d cimp %d (sameas %d)\n", (int)clist, (int)cimp, dc.same_as);
#endif
}
if (nolig || (!clist && !dc.same_as)) {
/* if user has prohibited the ligature from
* being used, or if no ligature was found....
* consider the last consonant, and follow the form for
* its CONS..SINGLE form
Following this path also creates funny <cons>....<cons>ra-<cons>
sequences, i.e, the ra-<consonant> at the end of a letter
screws up things since in hindi mode the ra-<consonant> uses
some funky char lists .. (see dvnc.ifm, dvng.ifm)
BUT the damage here is preferable to be one if the ligature is used..
*/
dc = fptr->khadi[c2];
if (dc.cus) clist = dc.cus[form];
c2only = TRUE;
}
#ifdef DEBUG
fprintf(stderr, "consmany: clist is %d cimp %d sameas %d c1 %d\n", (int)clist, (int)cimp, dc.same_as, c1);
#endif /*DEBUG*/
break;
case VOWEL_TYPE:
dc = fptr->khadi[form];
form = A_FORM;
if (dc.cus) {
clist = dc.cus[form];
cimp = dc.cus[IMPLICIT_FORM];
}
break;
case SPECIAL_TYPE:
dc = fptr->khadi[c1];
form = IMPLICIT_FORM;
if (dc.cus) {
clist = dc.cus[form];
cimp = dc.cus[IMPLICIT_FORM];
}
break;
} /* switch */
if (clist && c2only) {
/* this clist has been obtained from the c2 consonant.
* Since c1 is omitted here, make sure that clist contains
* a reference to "implicit", that way make_letter will
* add in the chars for c1 too.
*/
lcus = clist;
found = FALSE;
while (lcus) {
if (lcus->u_pschar == IMPLICIT_PSCHAR) found = TRUE;
lcus = lcus->next;
}
if (!found) {
*lastform = dlet.v;
clist = &S_implicit_cu;
}
}
/* follow the same_as pointers until get required clist */
next = dc.same_as;
while (!clist && next) {
if (next->cus) clist = next->cus[form];
#ifdef DEBUG
fprintf(stderr, "getcons: following sam_as pointer clist is %d\n", (int)clist);
#endif /*DEBUG*/
next = next->same_as;
}
if (!clist) {
fprintf(stderr, "*** Error (line %d): comp_units missing (in %s) for this letter:\n",
G_lineno, fptr->fname);
for (i = 0; i < dlet.n; i ++) {
form = dlet.cons[i];
fprintf(stderr, "*** Consonant %d: token (%d), IFM name (%s)\n",
i,form,G_ifm_map[form-A_TOK].codename);
}
if (dlet.v < A_TOK)
fprintf(stderr, "*** Vowel: token (%d), IFM name (%s)\n",
dlet.v+OFFSET_TOK, G_ifm_map[dlet.v].codename);
else
fprintf(stderr, "*** Vowel: token (%d), IFM name (%s)\n", dlet.v,
G_ifm_map[dlet.v-A_TOK].codename);
fprintf(stderr, "***\n");
return FALSE;
}
*cus = clist;
*imp = cimp;
return TRUE;
} /* S_get_cus_form() */
/* =================================================================== */
static int S_add_cus(pschar_t psfm[], comp_unit_t* pcu, comp_unit_t cu)
{
int n, w;
*pcu = cu;
n = 1;
/* XXX need to track bounding boxes etc */
/* if this is a zero with char, add one more comp unit */
if (cu.u_pschar >= 0 && cu.u_pschar <= 255) {
w = psfm[cu.u_pschar].w;
if (w == 0) { /* reapply delta to get back at current pos*/
pcu++;
pcu->deltax = -cu.deltax;
/* pcu->deltay = -cu.deltay; */
pcu->deltay = 0; /* no Y delta, since Y movements are always
* restored back to correct Y value
* by the cus_to_tex() and cus_to_ps()
* functions...
*/
pcu->u_pschar = NO_PSCHAR; /* just delta */
n++;
}
}
return n;
}
/* ============================^ dchar.c ^ =========================== */